Skip to content

Commit f54106f

Browse files
committed
Fix full-table-vacuum request mechanism for MultiXactIds
While autovacuum dutifully launched anti-multixact-wraparound vacuums when the multixact "age" was reached, the vacuum code was not aware that it needed to make them be full table vacuums. As the resulting partial-table vacuums aren't capable of actually increasing relminmxid, autovacuum continued to launch anti-wraparound vacuums that didn't have the intended effect, until age of relfrozenxid caused the vacuum to finally be a full table one via vacuum_freeze_table_age. To fix, introduce logic for multixacts similar to that for plain TransactionIds, using the same GUCs. Backpatch to 9.3, where permanent MultiXactIds were introduced. Andres Freund, some cleanup by Álvaro
1 parent 76a31c6 commit f54106f

File tree

6 files changed

+87
-28
lines changed

6 files changed

+87
-28
lines changed

src/backend/access/transam/multixact.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,21 @@ MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
23742374
return (diff < 0);
23752375
}
23762376

2377+
/*
2378+
* MultiXactIdPrecedesOrEquals -- is multi1 logically <= multi2?
2379+
*
2380+
* XXX do we need to do something special for InvalidMultiXactId?
2381+
* (Doesn't look like it.)
2382+
*/
2383+
bool
2384+
MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
2385+
{
2386+
int32 diff = (int32) (multi1 - multi2);
2387+
2388+
return (diff <= 0);
2389+
}
2390+
2391+
23772392
/*
23782393
* Decide which of two offsets is earlier.
23792394
*/

src/backend/commands/cluster.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
176176
/* close relation, keep lock till commit */
177177
heap_close(rel, NoLock);
178178

179-
/* Do the job */
179+
/*
180+
* Do the job. We use a -1 freeze_min_age to avoid having CLUSTER
181+
* freeze tuples earlier than a plain VACUUM would.
182+
*/
180183
cluster_rel(tableOid, indexOid, false, stmt->verbose, -1, -1);
181184
}
182185
else
@@ -226,6 +229,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
226229
StartTransactionCommand();
227230
/* functions in indexes may want a snapshot set */
228231
PushActiveSnapshot(GetTransactionSnapshot());
232+
/* Do the job. As above, use a -1 freeze_min_age. */
229233
cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose,
230234
-1, -1);
231235
PopActiveSnapshot();
@@ -853,13 +857,12 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
853857
*pSwapToastByContent = false;
854858

855859
/*
856-
* compute xids used to freeze and weed out dead tuples. We use -1
857-
* freeze_min_age to avoid having CLUSTER freeze tuples earlier than a
858-
* plain VACUUM would.
860+
* compute xids used to freeze and weed out dead tuples.
859861
*/
860862
vacuum_set_xid_limits(freeze_min_age, freeze_table_age,
861863
OldHeap->rd_rel->relisshared,
862-
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff);
864+
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
865+
NULL);
863866

864867
/*
865868
* FreezeXid will become the table's new relfrozenxid, and that mustn't go

src/backend/commands/vacuum.c

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -376,19 +376,39 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
376376

377377
/*
378378
* vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points
379+
*
380+
* The output parameters are:
381+
* - oldestXmin is the cutoff value used to distinguish whether tuples are
382+
* DEAD or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
383+
* - freezeLimit is the Xid below which all Xids are replaced by
384+
* FrozenTransactionId during vacuum.
385+
* - xidFullScanLimit (computed from the the table_freeze_age parameter)
386+
* represents a minimum Xid value; a table whose relfrozenxid is older than
387+
* this will have a full-table vacuum applied to it, to freeze tuples across
388+
* the whole table. Vacuuming a table younger than this value can use a
389+
* partial scan.
390+
* - multiXactCutoff is the value below which all MultiXactIds are removed from
391+
* Xmax.
392+
* - mxactFullScanLimit is a value against which a table's relminmxid value is
393+
* compared to produce a full-table vacuum, as with xidFullScanLimit.
394+
*
395+
* xidFullScanLimit and mxactFullScanLimit can be passed as NULL if caller is
396+
* not interested.
379397
*/
380398
void
381399
vacuum_set_xid_limits(int freeze_min_age,
382400
int freeze_table_age,
383401
bool sharedRel,
384402
TransactionId *oldestXmin,
385403
TransactionId *freezeLimit,
386-
TransactionId *freezeTableLimit,
387-
MultiXactId *multiXactCutoff)
404+
TransactionId *xidFullScanLimit,
405+
MultiXactId *multiXactCutoff,
406+
MultiXactId *mxactFullScanLimit)
388407
{
389408
int freezemin;
390409
TransactionId limit;
391410
TransactionId safeLimit;
411+
MultiXactId mxactLimit;
392412

393413
/*
394414
* We can always ignore processes running lazy vacuum. This is because we
@@ -441,10 +461,22 @@ vacuum_set_xid_limits(int freeze_min_age,
441461

442462
*freezeLimit = limit;
443463

444-
if (freezeTableLimit != NULL)
464+
/*
465+
* simplistic MultiXactId removal limit: use the same policy as for
466+
* freezing Xids (except we use the oldest known mxact instead of the
467+
* current next value).
468+
*/
469+
mxactLimit = GetOldestMultiXactId() - freezemin;
470+
if (mxactLimit < FirstMultiXactId)
471+
mxactLimit = FirstMultiXactId;
472+
*multiXactCutoff = mxactLimit;
473+
474+
if (xidFullScanLimit != NULL)
445475
{
446476
int freezetable;
447477

478+
Assert(mxactFullScanLimit != NULL);
479+
448480
/*
449481
* Determine the table freeze age to use: as specified by the caller,
450482
* or vacuum_freeze_table_age, but in any case not more than
@@ -459,29 +491,25 @@ vacuum_set_xid_limits(int freeze_min_age,
459491
Assert(freezetable >= 0);
460492

461493
/*
462-
* Compute the cutoff XID, being careful not to generate a "permanent"
463-
* XID.
494+
* Compute XID limit causing a full-table vacuum, being careful not to
495+
* generate a "permanent" XID.
464496
*/
465497
limit = ReadNewTransactionId() - freezetable;
466498
if (!TransactionIdIsNormal(limit))
467499
limit = FirstNormalTransactionId;
468500

469-
*freezeTableLimit = limit;
470-
}
471-
472-
if (multiXactCutoff != NULL)
473-
{
474-
MultiXactId mxLimit;
501+
*xidFullScanLimit = limit;
475502

476503
/*
477-
* simplistic multixactid freezing: use the same freezing policy as
478-
* for Xids
504+
* Compute MultiXactId limit to cause a full-table vacuum, being
505+
* careful not to generate an invalid multi. We just copy the logic
506+
* (and limits) from plain XIDs here.
479507
*/
480-
mxLimit = GetOldestMultiXactId() - freezemin;
481-
if (mxLimit < FirstMultiXactId)
482-
mxLimit = FirstMultiXactId;
508+
mxactLimit = ReadNextMultiXactId() - freezetable;
509+
if (mxactLimit < FirstMultiXactId)
510+
mxactLimit = FirstMultiXactId;
483511

484-
*multiXactCutoff = mxLimit;
512+
*mxactFullScanLimit = mxactLimit;
485513
}
486514
}
487515

src/backend/commands/vacuumlazy.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
180180
write_rate;
181181
bool scan_all; /* should we scan all pages? */
182182
bool scanned_all; /* did we actually scan all pages? */
183-
TransactionId freezeTableLimit;
183+
TransactionId xidFullScanLimit;
184+
MultiXactId mxactFullScanLimit;
184185
BlockNumber new_rel_pages;
185186
double new_rel_tuples;
186187
BlockNumber new_rel_allvisible;
@@ -203,10 +204,19 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
203204

204205
vacuum_set_xid_limits(vacstmt->freeze_min_age, vacstmt->freeze_table_age,
205206
onerel->rd_rel->relisshared,
206-
&OldestXmin, &FreezeLimit, &freezeTableLimit,
207-
&MultiXactCutoff);
207+
&OldestXmin, &FreezeLimit, &xidFullScanLimit,
208+
&MultiXactCutoff, &mxactFullScanLimit);
209+
210+
/*
211+
* We request a full scan if either the table's frozen Xid is now older
212+
* than or equal to the requested Xid full-table scan limit; or if the
213+
* table's minimum MultiXactId is older than or equal to the requested mxid
214+
* full-table scan limit.
215+
*/
208216
scan_all = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid,
209-
freezeTableLimit);
217+
xidFullScanLimit);
218+
scan_all |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid,
219+
mxactFullScanLimit);
210220

211221
vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
212222

src/include/access/multixact.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ extern void MultiXactIdSetOldestMember(void);
8787
extern int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **xids,
8888
bool allow_old);
8989
extern bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2);
90+
extern bool MultiXactIdPrecedesOrEquals(MultiXactId multi1,
91+
MultiXactId multi2);
9092

9193
extern void AtEOXact_MultiXact(void);
9294
extern void AtPrepare_MultiXact(void);

src/include/commands/vacuum.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,9 @@ extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age,
159159
bool sharedRel,
160160
TransactionId *oldestXmin,
161161
TransactionId *freezeLimit,
162-
TransactionId *freezeTableLimit,
163-
MultiXactId *multiXactCutoff);
162+
TransactionId *xidFullScanLimit,
163+
MultiXactId *multiXactCutoff,
164+
MultiXactId *mxactFullScanLimit);
164165
extern void vac_update_datfrozenxid(void);
165166
extern void vacuum_delay_point(void);
166167

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy