Aggressively freeze tables when CLUSTER or VACUUM FULL rewrites them.
We haven't wanted to do this in the past on the grounds that in rare
cases the original xmin value will be needed for forensic purposes, but
commit 37484ad2aa
removes that objection,
so now we can.
Per extensive discussion, among many people, on pgsql-hackers.
This commit is contained in:
parent
4cf81b737d
commit
3cff1879f8
|
@ -102,7 +102,9 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">
|
||||||
Specifying <literal>FREEZE</literal> is equivalent to performing
|
Specifying <literal>FREEZE</literal> is equivalent to performing
|
||||||
<command>VACUUM</command> with the
|
<command>VACUUM</command> with the
|
||||||
<xref linkend="guc-vacuum-freeze-min-age"> parameter
|
<xref linkend="guc-vacuum-freeze-min-age"> parameter
|
||||||
set to zero.
|
set to zero. Aggressive freezing is always performed when the
|
||||||
|
table is rewritten, so this option is redundant when <literal>FULL</>
|
||||||
|
is specified.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
|
@ -345,7 +345,7 @@ rewrite_heap_tuple(RewriteState state,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* While we have our hands on the tuple, we may as well freeze any
|
* While we have our hands on the tuple, we may as well freeze any
|
||||||
* very-old xmin or xmax, so that future VACUUM effort can be saved.
|
* eligible xmin or xmax, so that future VACUUM effort can be saved.
|
||||||
*/
|
*/
|
||||||
heap_freeze_tuple(new_tuple->t_data, state->rs_freeze_xid,
|
heap_freeze_tuple(new_tuple->t_data, state->rs_freeze_xid,
|
||||||
state->rs_cutoff_multi);
|
state->rs_cutoff_multi);
|
||||||
|
|
|
@ -64,12 +64,10 @@ typedef struct
|
||||||
} RelToCluster;
|
} RelToCluster;
|
||||||
|
|
||||||
|
|
||||||
static void rebuild_relation(Relation OldHeap, Oid indexOid,
|
static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose);
|
||||||
int freeze_min_age, int freeze_table_age, bool verbose);
|
|
||||||
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
|
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
|
||||||
int freeze_min_age, int freeze_table_age, bool verbose,
|
bool verbose, bool *pSwapToastByContent,
|
||||||
bool *pSwapToastByContent, TransactionId *pFreezeXid,
|
TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
|
||||||
MultiXactId *pCutoffMulti);
|
|
||||||
static List *get_tables_to_cluster(MemoryContext cluster_context);
|
static List *get_tables_to_cluster(MemoryContext cluster_context);
|
||||||
static void reform_and_rewrite_tuple(HeapTuple tuple,
|
static void reform_and_rewrite_tuple(HeapTuple tuple,
|
||||||
TupleDesc oldTupDesc, TupleDesc newTupDesc,
|
TupleDesc oldTupDesc, TupleDesc newTupDesc,
|
||||||
|
@ -176,11 +174,8 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
|
||||||
/* close relation, keep lock till commit */
|
/* close relation, keep lock till commit */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
/* Do the job. */
|
||||||
* Do the job. We use a -1 freeze_min_age to avoid having CLUSTER
|
cluster_rel(tableOid, indexOid, false, stmt->verbose);
|
||||||
* freeze tuples earlier than a plain VACUUM would.
|
|
||||||
*/
|
|
||||||
cluster_rel(tableOid, indexOid, false, stmt->verbose, -1, -1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -229,9 +224,8 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
/* functions in indexes may want a snapshot set */
|
/* functions in indexes may want a snapshot set */
|
||||||
PushActiveSnapshot(GetTransactionSnapshot());
|
PushActiveSnapshot(GetTransactionSnapshot());
|
||||||
/* Do the job. As above, use a -1 freeze_min_age. */
|
/* Do the job. */
|
||||||
cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose,
|
cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose);
|
||||||
-1, -1);
|
|
||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
}
|
}
|
||||||
|
@ -262,8 +256,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
|
||||||
* and error messages should refer to the operation as VACUUM not CLUSTER.
|
* and error messages should refer to the operation as VACUUM not CLUSTER.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose,
|
cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose)
|
||||||
int freeze_min_age, int freeze_table_age)
|
|
||||||
{
|
{
|
||||||
Relation OldHeap;
|
Relation OldHeap;
|
||||||
|
|
||||||
|
@ -407,8 +400,7 @@ cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose,
|
||||||
TransferPredicateLocksToHeapRelation(OldHeap);
|
TransferPredicateLocksToHeapRelation(OldHeap);
|
||||||
|
|
||||||
/* rebuild_relation does all the dirty work */
|
/* rebuild_relation does all the dirty work */
|
||||||
rebuild_relation(OldHeap, indexOid, freeze_min_age, freeze_table_age,
|
rebuild_relation(OldHeap, indexOid, verbose);
|
||||||
verbose);
|
|
||||||
|
|
||||||
/* NB: rebuild_relation does heap_close() on OldHeap */
|
/* NB: rebuild_relation does heap_close() on OldHeap */
|
||||||
}
|
}
|
||||||
|
@ -561,8 +553,7 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
|
||||||
* NB: this routine closes OldHeap at the right time; caller should not.
|
* NB: this routine closes OldHeap at the right time; caller should not.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
rebuild_relation(Relation OldHeap, Oid indexOid,
|
rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
|
||||||
int freeze_min_age, int freeze_table_age, bool verbose)
|
|
||||||
{
|
{
|
||||||
Oid tableOid = RelationGetRelid(OldHeap);
|
Oid tableOid = RelationGetRelid(OldHeap);
|
||||||
Oid tableSpace = OldHeap->rd_rel->reltablespace;
|
Oid tableSpace = OldHeap->rd_rel->reltablespace;
|
||||||
|
@ -587,8 +578,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
|
||||||
AccessExclusiveLock);
|
AccessExclusiveLock);
|
||||||
|
|
||||||
/* Copy the heap data into the new table in the desired order */
|
/* Copy the heap data into the new table in the desired order */
|
||||||
copy_heap_data(OIDNewHeap, tableOid, indexOid,
|
copy_heap_data(OIDNewHeap, tableOid, indexOid, verbose,
|
||||||
freeze_min_age, freeze_table_age, verbose,
|
|
||||||
&swap_toast_by_content, &frozenXid, &cutoffMulti);
|
&swap_toast_by_content, &frozenXid, &cutoffMulti);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -743,8 +733,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
|
||||||
* *pCutoffMulti receives the MultiXactId used as a cutoff point.
|
* *pCutoffMulti receives the MultiXactId used as a cutoff point.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
|
copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
|
||||||
int freeze_min_age, int freeze_table_age, bool verbose,
|
|
||||||
bool *pSwapToastByContent, TransactionId *pFreezeXid,
|
bool *pSwapToastByContent, TransactionId *pFreezeXid,
|
||||||
MultiXactId *pCutoffMulti)
|
MultiXactId *pCutoffMulti)
|
||||||
{
|
{
|
||||||
|
@ -857,10 +846,11 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
|
||||||
*pSwapToastByContent = false;
|
*pSwapToastByContent = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* compute xids used to freeze and weed out dead tuples.
|
* Compute xids used to freeze and weed out dead tuples and multixacts.
|
||||||
|
* Since we're going to rewrite the whole table anyway, there's no reason
|
||||||
|
* not to be aggressive about this.
|
||||||
*/
|
*/
|
||||||
vacuum_set_xid_limits(freeze_min_age, freeze_table_age,
|
vacuum_set_xid_limits(0, 0, OldHeap->rd_rel->relisshared,
|
||||||
OldHeap->rd_rel->relisshared,
|
|
||||||
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
|
&OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
|
|
@ -1149,8 +1149,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
|
||||||
|
|
||||||
/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
|
/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
|
||||||
cluster_rel(relid, InvalidOid, false,
|
cluster_rel(relid, InvalidOid, false,
|
||||||
(vacstmt->options & VACOPT_VERBOSE) != 0,
|
(vacstmt->options & VACOPT_VERBOSE) != 0);
|
||||||
vacstmt->freeze_min_age, vacstmt->freeze_table_age);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
|
lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
extern void cluster(ClusterStmt *stmt, bool isTopLevel);
|
extern void cluster(ClusterStmt *stmt, bool isTopLevel);
|
||||||
extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
|
extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
|
||||||
bool verbose, int freeze_min_age, int freeze_table_age);
|
bool verbose);
|
||||||
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
|
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
|
||||||
bool recheck, LOCKMODE lockmode);
|
bool recheck, LOCKMODE lockmode);
|
||||||
extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
|
extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
|
||||||
|
|
Loading…
Reference in New Issue