@@ -956,24 +956,25 @@ get_all_vacuum_rels(int options)
956956bool
957957vacuum_set_xid_limits (Relation rel ,
958958 int freeze_min_age ,
959- int freeze_table_age ,
960959 int multixact_freeze_min_age ,
960+ int freeze_table_age ,
961961 int multixact_freeze_table_age ,
962962 TransactionId * oldestXmin ,
963963 MultiXactId * oldestMxact ,
964964 TransactionId * freezeLimit ,
965965 MultiXactId * multiXactCutoff )
966966{
967- int freezemin ;
968- int mxid_freezemin ;
967+ TransactionId nextXID ,
968+ safeOldestXmin ,
969+ aggressiveXIDCutoff ;
970+ MultiXactId nextMXID ,
971+ safeOldestMxact ,
972+ aggressiveMXIDCutoff ;
969973 int effective_multixact_freeze_max_age ;
970- TransactionId limit ;
971- TransactionId safeLimit ;
972- MultiXactId mxactLimit ;
973- MultiXactId safeMxactLimit ;
974- int freezetable ;
975974
976975 /*
976+ * Acquire oldestXmin.
977+ *
977978 * We can always ignore processes running lazy vacuum. This is because we
978979 * use these values only for deciding which tuples we must keep in the
979980 * tables. Since lazy vacuum doesn't write its XID anywhere (usually no
@@ -1005,44 +1006,32 @@ vacuum_set_xid_limits(Relation rel,
10051006
10061007 Assert (TransactionIdIsNormal (* oldestXmin ));
10071008
1009+ /* Acquire oldestMxact */
1010+ * oldestMxact = GetOldestMultiXactId ();
1011+ Assert (MultiXactIdIsValid (* oldestMxact ));
1012+
1013+ /* Acquire next XID/next MXID values used to apply age-based settings */
1014+ nextXID = ReadNextTransactionId ();
1015+ nextMXID = ReadNextMultiXactId ();
1016+
10081017 /*
10091018 * Determine the minimum freeze age to use: as specified by the caller, or
10101019 * vacuum_freeze_min_age, but in any case not more than half
10111020 * autovacuum_freeze_max_age, so that autovacuums to prevent XID
10121021 * wraparound won't occur too frequently.
10131022 */
1014- freezemin = freeze_min_age ;
1015- if (freezemin < 0 )
1016- freezemin = vacuum_freeze_min_age ;
1017- freezemin = Min (freezemin , autovacuum_freeze_max_age / 2 );
1018- Assert (freezemin >= 0 );
1023+ if (freeze_min_age < 0 )
1024+ freeze_min_age = vacuum_freeze_min_age ;
1025+ freeze_min_age = Min (freeze_min_age , autovacuum_freeze_max_age / 2 );
1026+ Assert (freeze_min_age >= 0 );
10191027
1020- /*
1021- * Compute the cutoff XID, being careful not to generate a "permanent" XID
1022- */
1023- limit = * oldestXmin - freezemin ;
1024- if (!TransactionIdIsNormal (limit ))
1025- limit = FirstNormalTransactionId ;
1026-
1027- /*
1028- * If oldestXmin is very far back (in practice, more than
1029- * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum
1030- * freeze age of zero.
1031- */
1032- safeLimit = ReadNextTransactionId () - autovacuum_freeze_max_age ;
1033- if (!TransactionIdIsNormal (safeLimit ))
1034- safeLimit = FirstNormalTransactionId ;
1035-
1036- if (TransactionIdPrecedes (limit , safeLimit ))
1037- {
1038- ereport (WARNING ,
1039- (errmsg ("oldest xmin is far in the past" ),
1040- errhint ("Close open transactions soon to avoid wraparound problems.\n"
1041- "You might also need to commit or roll back old prepared transactions, or drop stale replication slots." )));
1042- limit = * oldestXmin ;
1043- }
1044-
1045- * freezeLimit = limit ;
1028+ /* Compute freezeLimit, being careful to generate a normal XID */
1029+ * freezeLimit = nextXID - freeze_min_age ;
1030+ if (!TransactionIdIsNormal (* freezeLimit ))
1031+ * freezeLimit = FirstNormalTransactionId ;
1032+ /* freezeLimit must always be <= oldestXmin */
1033+ if (TransactionIdPrecedes (* oldestXmin , * freezeLimit ))
1034+ * freezeLimit = * oldestXmin ;
10461035
10471036 /*
10481037 * Compute the multixact age for which freezing is urgent. This is
@@ -1057,93 +1046,83 @@ vacuum_set_xid_limits(Relation rel,
10571046 * than half effective_multixact_freeze_max_age, so that autovacuums to
10581047 * prevent MultiXact wraparound won't occur too frequently.
10591048 */
1060- mxid_freezemin = multixact_freeze_min_age ;
1061- if (mxid_freezemin < 0 )
1062- mxid_freezemin = vacuum_multixact_freeze_min_age ;
1063- mxid_freezemin = Min (mxid_freezemin ,
1064- effective_multixact_freeze_max_age / 2 );
1065- Assert (mxid_freezemin >= 0 );
1066-
1067- /* Remember for caller */
1068- * oldestMxact = GetOldestMultiXactId ();
1069-
1070- /* compute the cutoff multi, being careful to generate a valid value */
1071- mxactLimit = * oldestMxact - mxid_freezemin ;
1072- if (mxactLimit < FirstMultiXactId )
1073- mxactLimit = FirstMultiXactId ;
1074-
1075- safeMxactLimit =
1076- ReadNextMultiXactId () - effective_multixact_freeze_max_age ;
1077- if (safeMxactLimit < FirstMultiXactId )
1078- safeMxactLimit = FirstMultiXactId ;
1079-
1080- if (MultiXactIdPrecedes (mxactLimit , safeMxactLimit ))
1081- {
1049+ if (multixact_freeze_min_age < 0 )
1050+ multixact_freeze_min_age = vacuum_multixact_freeze_min_age ;
1051+ multixact_freeze_min_age = Min (multixact_freeze_min_age ,
1052+ effective_multixact_freeze_max_age / 2 );
1053+ Assert (multixact_freeze_min_age >= 0 );
1054+
1055+ /* Compute multiXactCutoff, being careful to generate a valid value */
1056+ * multiXactCutoff = nextMXID - multixact_freeze_min_age ;
1057+ if (* multiXactCutoff < FirstMultiXactId )
1058+ * multiXactCutoff = FirstMultiXactId ;
1059+ /* multiXactCutoff must always be <= oldestMxact */
1060+ if (MultiXactIdPrecedes (* oldestMxact , * multiXactCutoff ))
1061+ * multiXactCutoff = * oldestMxact ;
1062+
1063+ /*
1064+ * Done setting output parameters; check if oldestXmin or oldestMxact are
1065+ * held back to an unsafe degree in passing
1066+ */
1067+ safeOldestXmin = nextXID - autovacuum_freeze_max_age ;
1068+ if (!TransactionIdIsNormal (safeOldestXmin ))
1069+ safeOldestXmin = FirstNormalTransactionId ;
1070+ safeOldestMxact = nextMXID - effective_multixact_freeze_max_age ;
1071+ if (safeOldestMxact < FirstMultiXactId )
1072+ safeOldestMxact = FirstMultiXactId ;
1073+ if (TransactionIdPrecedes (* oldestXmin , safeOldestXmin ))
10821074 ereport (WARNING ,
1083- (errmsg ("oldest multixact is far in the past" ),
1084- errhint ("Close open transactions with multixacts soon to avoid wraparound problems." )));
1085- /* Use the safe limit, unless an older mxact is still running */
1086- if (MultiXactIdPrecedes (* oldestMxact , safeMxactLimit ))
1087- mxactLimit = * oldestMxact ;
1088- else
1089- mxactLimit = safeMxactLimit ;
1090- }
1091-
1092- * multiXactCutoff = mxactLimit ;
1075+ (errmsg ("cutoff for removing and freezing tuples is far in the past" ),
1076+ errhint ("Close open transactions soon to avoid wraparound problems.\n"
1077+ "You might also need to commit or roll back old prepared transactions, or drop stale replication slots." )));
1078+ if (MultiXactIdPrecedes (* oldestMxact , safeOldestMxact ))
1079+ ereport (WARNING ,
1080+ (errmsg ("cutoff for freezing multixacts is far in the past" ),
1081+ errhint ("Close open transactions soon to avoid wraparound problems.\n"
1082+ "You might also need to commit or roll back old prepared transactions, or drop stale replication slots." )));
10931083
10941084 /*
1095- * Done setting output parameters; just need to figure out if caller needs
1096- * to do an aggressive VACUUM or not.
1085+ * Finally, figure out if caller needs to do an aggressive VACUUM or not.
10971086 *
10981087 * Determine the table freeze age to use: as specified by the caller, or
1099- * vacuum_freeze_table_age, but in any case not more than
1100- * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
1101- * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples
1102- * before anti-wraparound autovacuum is launched.
1103- */
1104- freezetable = freeze_table_age ;
1105- if (freezetable < 0 )
1106- freezetable = vacuum_freeze_table_age ;
1107- freezetable = Min (freezetable , autovacuum_freeze_max_age * 0.95 );
1108- Assert (freezetable >= 0 );
1109-
1110- /*
1111- * Compute XID limit causing an aggressive vacuum, being careful not to
1112- * generate a "permanent" XID
1113- */
1114- limit = ReadNextTransactionId () - freezetable ;
1115- if (!TransactionIdIsNormal (limit ))
1116- limit = FirstNormalTransactionId ;
1088+ * the value of the vacuum_freeze_table_age GUC, but in any case not more
1089+ * than autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly
1090+ * VACUUM schedule, the nightly VACUUM gets a chance to freeze XIDs before
1091+ * anti-wraparound autovacuum is launched.
1092+ */
1093+ if (freeze_table_age < 0 )
1094+ freeze_table_age = vacuum_freeze_table_age ;
1095+ freeze_table_age = Min (freeze_table_age , autovacuum_freeze_max_age * 0.95 );
1096+ Assert (freeze_table_age >= 0 );
1097+ aggressiveXIDCutoff = nextXID - freeze_table_age ;
1098+ if (!TransactionIdIsNormal (aggressiveXIDCutoff ))
1099+ aggressiveXIDCutoff = FirstNormalTransactionId ;
11171100 if (TransactionIdPrecedesOrEquals (rel -> rd_rel -> relfrozenxid ,
1118- limit ))
1101+ aggressiveXIDCutoff ))
11191102 return true;
11201103
11211104 /*
11221105 * Similar to the above, determine the table freeze age to use for
1123- * multixacts: as specified by the caller, or
1124- * vacuum_multixact_freeze_table_age, but in any case not more than
1125- * autovacuum_multixact_freeze_table_age * 0.95, so that if you have e.g.
1106+ * multixacts: as specified by the caller, or the value of the
1107+ * vacuum_multixact_freeze_table_age GUC , but in any case not more than
1108+ * effective_multixact_freeze_max_age * 0.95, so that if you have e.g.
11261109 * nightly VACUUM schedule, the nightly VACUUM gets a chance to freeze
11271110 * multixacts before anti-wraparound autovacuum is launched.
11281111 */
1129- freezetable = multixact_freeze_table_age ;
1130- if (freezetable < 0 )
1131- freezetable = vacuum_multixact_freeze_table_age ;
1132- freezetable = Min (freezetable ,
1133- effective_multixact_freeze_max_age * 0.95 );
1134- Assert (freezetable >= 0 );
1135-
1136- /*
1137- * Compute MultiXact limit causing an aggressive vacuum, being careful to
1138- * generate a valid MultiXact value
1139- */
1140- mxactLimit = ReadNextMultiXactId () - freezetable ;
1141- if (mxactLimit < FirstMultiXactId )
1142- mxactLimit = FirstMultiXactId ;
1112+ if (multixact_freeze_table_age < 0 )
1113+ multixact_freeze_table_age = vacuum_multixact_freeze_table_age ;
1114+ multixact_freeze_table_age =
1115+ Min (multixact_freeze_table_age ,
1116+ effective_multixact_freeze_max_age * 0.95 );
1117+ Assert (multixact_freeze_table_age >= 0 );
1118+ aggressiveMXIDCutoff = nextMXID - multixact_freeze_table_age ;
1119+ if (aggressiveMXIDCutoff < FirstMultiXactId )
1120+ aggressiveMXIDCutoff = FirstMultiXactId ;
11431121 if (MultiXactIdPrecedesOrEquals (rel -> rd_rel -> relminmxid ,
1144- mxactLimit ))
1122+ aggressiveMXIDCutoff ))
11451123 return true;
11461124
1125+ /* Non-aggressive VACUUM */
11471126 return false;
11481127}
11491128
0 commit comments