return (diff < 0);
}
+/*
+ * MultiXactIdPrecedesOrEquals -- is multi1 logically <= multi2?
+ *
+ * XXX do we need to do something special for InvalidMultiXactId?
+ * (Doesn't look like it.)
+ */
+bool
+MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
+{
+ int32 diff = (int32) (multi1 - multi2);
+
+ return (diff <= 0);
+}
+
+
/*
* Decide which of two offsets is earlier.
*/
/* close relation, keep lock till commit */
heap_close(rel, NoLock);
- /* Do the job */
+ /*
+ * Do the job. We use a -1 freeze_min_age to avoid having CLUSTER
+ * freeze tuples earlier than a plain VACUUM would.
+ */
cluster_rel(tableOid, indexOid, false, stmt->verbose, -1, -1);
}
else
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
PushActiveSnapshot(GetTransactionSnapshot());
+ /* Do the job. As above, use a -1 freeze_min_age. */
cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose,
-1, -1);
PopActiveSnapshot();
*pSwapToastByContent = false;
/*
- * compute xids used to freeze and weed out dead tuples. We use -1
- * freeze_min_age to avoid having CLUSTER freeze tuples earlier than a
- * plain VACUUM would.
+ * compute xids used to freeze and weed out dead tuples.
*/
vacuum_set_xid_limits(freeze_min_age, freeze_table_age,
OldHeap->rd_rel->relisshared,
- &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff);
+ &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
+ NULL);
/*
* FreezeXid will become the table's new relfrozenxid, and that mustn't go
/*
* vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points
+ *
+ * The output parameters are:
+ * - oldestXmin is the cutoff value used to distinguish whether tuples are
+ * DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
+ * - freezeLimit is the Xid below which all Xids are replaced by
+ * FrozenTransactionId during vacuum.
+ * - xidFullScanLimit (computed from the the table_freeze_age parameter)
+ * represents a minimum Xid value; a table whose relfrozenxid is older than
+ * this will have a full-table vacuum applied to it, to freeze tuples across
+ * the whole table. Vacuuming a table younger than this value can use a
+ * partial scan.
+ * - multiXactCutoff is the value below which all MultiXactIds are removed from
+ * Xmax.
+ * - mxactFullScanLimit is a value against which a table's relminmxid value is
+ * compared to produce a full-table vacuum, as with xidFullScanLimit.
+ *
+ * xidFullScanLimit and mxactFullScanLimit can be passed as NULL if caller is
+ * not interested.
*/
void
vacuum_set_xid_limits(int freeze_min_age,
bool sharedRel,
TransactionId *oldestXmin,
TransactionId *freezeLimit,
- TransactionId *freezeTableLimit,
- MultiXactId *multiXactCutoff)
+ TransactionId *xidFullScanLimit,
+ MultiXactId *multiXactCutoff,
+ MultiXactId *mxactFullScanLimit)
{
int freezemin;
TransactionId limit;
TransactionId safeLimit;
+ MultiXactId mxactLimit;
/*
* We can always ignore processes running lazy vacuum. This is because we
*freezeLimit = limit;
- if (freezeTableLimit != NULL)
+ /*
+ * simplistic MultiXactId removal limit: use the same policy as for
+ * freezing Xids (except we use the oldest known mxact instead of the
+ * current next value).
+ */
+ mxactLimit = GetOldestMultiXactId() - freezemin;
+ if (mxactLimit < FirstMultiXactId)
+ mxactLimit = FirstMultiXactId;
+ *multiXactCutoff = mxactLimit;
+
+ if (xidFullScanLimit != NULL)
{
int freezetable;
+ Assert(mxactFullScanLimit != NULL);
+
/*
* Determine the table freeze age to use: as specified by the caller,
* or vacuum_freeze_table_age, but in any case not more than
Assert(freezetable >= 0);
/*
- * Compute the cutoff XID, being careful not to generate a "permanent"
- * XID.
+ * Compute XID limit causing a full-table vacuum, being careful not to
+ * generate a "permanent" XID.
*/
limit = ReadNewTransactionId() - freezetable;
if (!TransactionIdIsNormal(limit))
limit = FirstNormalTransactionId;
- *freezeTableLimit = limit;
- }
-
- if (multiXactCutoff != NULL)
- {
- MultiXactId mxLimit;
+ *xidFullScanLimit = limit;
/*
- * simplistic multixactid freezing: use the same freezing policy as
- * for Xids
+ * Compute MultiXactId limit to cause a full-table vacuum, being
+ * careful not to generate an invalid multi. We just copy the logic
+ * (and limits) from plain XIDs here.
*/
- mxLimit = GetOldestMultiXactId() - freezemin;
- if (mxLimit < FirstMultiXactId)
- mxLimit = FirstMultiXactId;
+ mxactLimit = ReadNextMultiXactId() - freezetable;
+ if (mxactLimit < FirstMultiXactId)
+ mxactLimit = FirstMultiXactId;
- *multiXactCutoff = mxLimit;
+ *mxactFullScanLimit = mxactLimit;
}
}
write_rate;
bool scan_all; /* should we scan all pages? */
bool scanned_all; /* did we actually scan all pages? */
- TransactionId freezeTableLimit;
+ TransactionId xidFullScanLimit;
+ MultiXactId mxactFullScanLimit;
BlockNumber new_rel_pages;
double new_rel_tuples;
BlockNumber new_rel_allvisible;
vacuum_set_xid_limits(vacstmt->freeze_min_age, vacstmt->freeze_table_age,
onerel->rd_rel->relisshared,
- &OldestXmin, &FreezeLimit, &freezeTableLimit,
- &MultiXactCutoff);
+ &OldestXmin, &FreezeLimit, &xidFullScanLimit,
+ &MultiXactCutoff, &mxactFullScanLimit);
+
+ /*
+ * We request a full scan if either the table's frozen Xid is now older
+ * than or equal to the requested Xid full-table scan limit; or if the
+ * table's minimum MultiXactId is older than or equal to the requested mxid
+ * full-table scan limit.
+ */
scan_all = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,
- freezeTableLimit);
+ xidFullScanLimit);
+ scan_all |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
+ mxactFullScanLimit);
vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
extern int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **xids,
bool allow_old);
extern bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2);
+extern bool MultiXactIdPrecedesOrEquals(MultiXactId multi1,
+ MultiXactId multi2);
extern void AtEOXact_MultiXact(void);
extern void AtPrepare_MultiXact(void);
bool sharedRel,
TransactionId *oldestXmin,
TransactionId *freezeLimit,
- TransactionId *freezeTableLimit,
- MultiXactId *multiXactCutoff);
+ TransactionId *xidFullScanLimit,
+ MultiXactId *multiXactCutoff,
+ MultiXactId *mxactFullScanLimit);
extern void vac_update_datfrozenxid(void);
extern void vacuum_delay_point(void);