@@ -1067,6 +1067,12 @@ vac_truncate_clog(TransactionId frozenXID,
10671067 /*
10681068 * Scan pg_database to compute the minimum datfrozenxid/datminmxid
10691069 *
1070+ * Since vac_update_datfrozenxid updates datfrozenxid/datminmxid in-place,
1071+ * the values could change while we look at them. Fetch each one just
1072+ * once to ensure sane behavior of the comparison logic. (Here, as in
1073+ * many other places, we assume that fetching or updating an XID in shared
1074+ * storage is atomic.)
1075+ *
10701076 * Note: we need not worry about a race condition with new entries being
10711077 * inserted by CREATE DATABASE. Any such entry will have a copy of some
10721078 * existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -1082,10 +1088,12 @@ vac_truncate_clog(TransactionId frozenXID,
10821088
10831089 while ((tuple = heap_getnext (scan , ForwardScanDirection )) != NULL )
10841090 {
1085- Form_pg_database dbform = (Form_pg_database ) GETSTRUCT (tuple );
1091+ volatile FormData_pg_database * dbform = (Form_pg_database ) GETSTRUCT (tuple );
1092+ TransactionId datfrozenxid = dbform -> datfrozenxid ;
1093+ TransactionId datminmxid = dbform -> datminmxid ;
10861094
1087- Assert (TransactionIdIsNormal (dbform -> datfrozenxid ));
1088- Assert (MultiXactIdIsValid (dbform -> datminmxid ));
1095+ Assert (TransactionIdIsNormal (datfrozenxid ));
1096+ Assert (MultiXactIdIsValid (datminmxid ));
10891097
10901098 /*
10911099 * If things are working properly, no database should have a
@@ -1096,21 +1104,21 @@ vac_truncate_clog(TransactionId frozenXID,
10961104 * databases have been scanned and cleaned up. (We will issue the
10971105 * "already wrapped" warning if appropriate, though.)
10981106 */
1099- if (TransactionIdPrecedes (lastSaneFrozenXid , dbform -> datfrozenxid ) ||
1100- MultiXactIdPrecedes (lastSaneMinMulti , dbform -> datminmxid ))
1107+ if (TransactionIdPrecedes (lastSaneFrozenXid , datfrozenxid ) ||
1108+ MultiXactIdPrecedes (lastSaneMinMulti , datminmxid ))
11011109 bogus = true;
11021110
1103- if (TransactionIdPrecedes (nextXID , dbform -> datfrozenxid ))
1111+ if (TransactionIdPrecedes (nextXID , datfrozenxid ))
11041112 frozenAlreadyWrapped = true;
1105- else if (TransactionIdPrecedes (dbform -> datfrozenxid , frozenXID ))
1113+ else if (TransactionIdPrecedes (datfrozenxid , frozenXID ))
11061114 {
1107- frozenXID = dbform -> datfrozenxid ;
1115+ frozenXID = datfrozenxid ;
11081116 oldestxid_datoid = HeapTupleGetOid (tuple );
11091117 }
11101118
1111- if (MultiXactIdPrecedes (dbform -> datminmxid , minMulti ))
1119+ if (MultiXactIdPrecedes (datminmxid , minMulti ))
11121120 {
1113- minMulti = dbform -> datminmxid ;
1121+ minMulti = datminmxid ;
11141122 minmulti_datoid = HeapTupleGetOid (tuple );
11151123 }
11161124 }
0 commit comments