aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/vacuum.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/vacuum.c')
-rw-r--r--src/backend/commands/vacuum.c96
1 files changed, 79 insertions, 17 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 2d3170a2504..a37a54e5b42 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -26,6 +26,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
+#include "access/multixact.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/namespace.h"
@@ -63,7 +64,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
-static void vac_truncate_clog(TransactionId frozenXID);
+static void vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti);
static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
bool for_wraparound);
@@ -379,7 +380,8 @@ vacuum_set_xid_limits(int freeze_min_age,
bool sharedRel,
TransactionId *oldestXmin,
TransactionId *freezeLimit,
- TransactionId *freezeTableLimit)
+ TransactionId *freezeTableLimit,
+ MultiXactId *multiXactFrzLimit)
{
int freezemin;
TransactionId limit;
@@ -463,8 +465,22 @@ vacuum_set_xid_limits(int freeze_min_age,
*freezeTableLimit = limit;
}
-}
+ if (multiXactFrzLimit != NULL)
+ {
+ MultiXactId mxLimit;
+
+ /*
+ * simplistic multixactid freezing: use the same freezing policy as
+ * for Xids
+ */
+ mxLimit = GetOldestMultiXactId() - freezemin;
+ if (mxLimit < FirstMultiXactId)
+ mxLimit = FirstMultiXactId;
+
+ *multiXactFrzLimit = mxLimit;
+ }
+}
/*
* vac_estimate_reltuples() -- estimate the new value for pg_class.reltuples
@@ -574,7 +590,8 @@ void
vac_update_relstats(Relation relation,
BlockNumber num_pages, double num_tuples,
BlockNumber num_all_visible_pages,
- bool hasindex, TransactionId frozenxid)
+ bool hasindex, TransactionId frozenxid,
+ MultiXactId minmulti)
{
Oid relid = RelationGetRelid(relation);
Relation rd;
@@ -648,6 +665,14 @@ vac_update_relstats(Relation relation,
dirty = true;
}
+ /* relminmxid must never go backward, either */
+ if (MultiXactIdIsValid(minmulti) &&
+ MultiXactIdPrecedes(pgcform->relminmxid, minmulti))
+ {
+ pgcform->relminmxid = minmulti;
+ dirty = true;
+ }
+
/* If anything changed, write out the tuple. */
if (dirty)
heap_inplace_update(rd, ctup);
@@ -660,8 +685,13 @@ vac_update_relstats(Relation relation,
* vac_update_datfrozenxid() -- update pg_database.datfrozenxid for our DB
*
* Update pg_database's datfrozenxid entry for our database to be the
- * minimum of the pg_class.relfrozenxid values. If we are able to
- * advance pg_database.datfrozenxid, also try to truncate pg_clog.
+ * minimum of the pg_class.relfrozenxid values.
+ *
+ * Similarly, update our datfrozenmulti to be the minimum of the
+ * pg_class.relfrozenmulti values.
+ *
+ * If we are able to advance either pg_database value, also try to
+ * truncate pg_clog and pg_multixact.
*
* We violate transaction semantics here by overwriting the database's
* existing pg_database tuple with the new value. This is reasonably
@@ -678,17 +708,24 @@ vac_update_datfrozenxid(void)
SysScanDesc scan;
HeapTuple classTup;
TransactionId newFrozenXid;
+ MultiXactId newFrozenMulti;
bool dirty = false;
/*
* Initialize the "min" calculation with GetOldestXmin, which is a
* reasonable approximation to the minimum relfrozenxid for not-yet-
* committed pg_class entries for new tables; see AddNewRelationTuple().
- * Se we cannot produce a wrong minimum by starting with this.
+ * So we cannot produce a wrong minimum by starting with this.
*/
newFrozenXid = GetOldestXmin(true, true);
/*
+ * Similarly, initialize the MultiXact "min" with the value that would
+ * be used on pg_class for new tables. See AddNewRelationTuple().
+ */
+ newFrozenMulti = GetOldestMultiXactId();
+
+ /*
* We must seqscan pg_class to find the minimum Xid, because there is no
* index that can help us here.
*/
@@ -710,9 +747,13 @@ vac_update_datfrozenxid(void)
continue;
Assert(TransactionIdIsNormal(classForm->relfrozenxid));
+ Assert(MultiXactIdIsValid(classForm->relminmxid));
if (TransactionIdPrecedes(classForm->relfrozenxid, newFrozenXid))
newFrozenXid = classForm->relfrozenxid;
+
+ if (MultiXactIdPrecedes(classForm->relminmxid, newFrozenMulti))
+ newFrozenMulti = classForm->relminmxid;
}
/* we're done with pg_class */
@@ -720,6 +761,7 @@ vac_update_datfrozenxid(void)
heap_close(relation, AccessShareLock);
Assert(TransactionIdIsNormal(newFrozenXid));
+ Assert(MultiXactIdIsValid(newFrozenMulti));
/* Now fetch the pg_database tuple we need to update. */
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
@@ -740,6 +782,13 @@ vac_update_datfrozenxid(void)
dirty = true;
}
+ /* ditto */
+ if (MultiXactIdPrecedes(dbform->datminmxid, newFrozenMulti))
+ {
+ dbform->datminmxid = newFrozenMulti;
+ dirty = true;
+ }
+
if (dirty)
heap_inplace_update(relation, tuple);
@@ -752,7 +801,7 @@ vac_update_datfrozenxid(void)
* this action will update that too.
*/
if (dirty || ForceTransactionIdLimitUpdate())
- vac_truncate_clog(newFrozenXid);
+ vac_truncate_clog(newFrozenXid, newFrozenMulti);
}
@@ -771,17 +820,19 @@ vac_update_datfrozenxid(void)
* info is stale.
*/
static void
-vac_truncate_clog(TransactionId frozenXID)
+vac_truncate_clog(TransactionId frozenXID, MultiXactId frozenMulti)
{
TransactionId myXID = GetCurrentTransactionId();
Relation relation;
HeapScanDesc scan;
HeapTuple tuple;
- Oid oldest_datoid;
+ Oid oldestxid_datoid;
+ Oid oldestmulti_datoid;
bool frozenAlreadyWrapped = false;
- /* init oldest_datoid to sync with my frozenXID */
- oldest_datoid = MyDatabaseId;
+ /* init oldest datoids to sync with my frozen values */
+ oldestxid_datoid = MyDatabaseId;
+ oldestmulti_datoid = MyDatabaseId;
/*
* Scan pg_database to compute the minimum datfrozenxid
@@ -804,13 +855,20 @@ vac_truncate_clog(TransactionId frozenXID)
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
Assert(TransactionIdIsNormal(dbform->datfrozenxid));
+ Assert(MultiXactIdIsValid(dbform->datminmxid));
if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
frozenAlreadyWrapped = true;
else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
{
frozenXID = dbform->datfrozenxid;
- oldest_datoid = HeapTupleGetOid(tuple);
+ oldestxid_datoid = HeapTupleGetOid(tuple);
+ }
+
+ if (MultiXactIdPrecedes(dbform->datminmxid, frozenMulti))
+ {
+ frozenMulti = dbform->datminmxid;
+ oldestmulti_datoid = HeapTupleGetOid(tuple);
}
}
@@ -832,14 +890,18 @@ vac_truncate_clog(TransactionId frozenXID)
return;
}
- /* Truncate CLOG to the oldest frozenxid */
+ /* Truncate CLOG and Multi to the oldest computed value */
TruncateCLOG(frozenXID);
+ TruncateMultiXact(frozenMulti);
/*
- * Update the wrap limit for GetNewTransactionId. Note: this function
- * will also signal the postmaster for an(other) autovac cycle if needed.
+ * Update the wrap limit for GetNewTransactionId and creation of new
+ * MultiXactIds. Note: these functions will also signal the postmaster for
+ * an(other) autovac cycle if needed. XXX should we avoid possibly
+ * signalling twice?
*/
- SetTransactionIdLimit(frozenXID, oldest_datoid);
+ SetTransactionIdLimit(frozenXID, oldestxid_datoid);
+ MultiXactAdvanceOldest(frozenMulti, oldestmulti_datoid);
}