mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
Remove vacuum_defer_cleanup_age
vacuum_defer_cleanup_age was introduced before hot_standby_feedback and
replication slots existed. It is hard to use reasonably - commonly it will
either be set too low (not preventing recovery conflicts, while still causing
some bloat), or too high (causing a lot of bloat). The alternatives do not
have that issue.
That on its own might not be sufficient reason to remove
vacuum_defer_cleanup_age, but it also complicates computation of xid
horizons. See e.g. the bug fixed in be504a3e97
. It also is untested.
This commit removes TransactionIdRetreatSafely(), as there are no users
anymore. There might be potential future users, hence noting that here.
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Justin Pryzby <pryzby@telsasoft.com>
Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/20230317230930.nhsgk3qfk7f4axls@awork3.anarazel.de
This commit is contained in:
@ -4614,41 +4614,6 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="guc-vacuum-defer-cleanup-age" xreflabel="vacuum_defer_cleanup_age">
|
|
||||||
<term><varname>vacuum_defer_cleanup_age</varname> (<type>integer</type>)
|
|
||||||
<indexterm>
|
|
||||||
<primary><varname>vacuum_defer_cleanup_age</varname> configuration parameter</primary>
|
|
||||||
</indexterm>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Specifies the number of transactions by which <command>VACUUM</command> and
|
|
||||||
<link linkend="storage-hot"><acronym>HOT</acronym> updates</link>
|
|
||||||
will defer cleanup of dead row versions. The
|
|
||||||
default is zero transactions, meaning that dead row versions can be
|
|
||||||
removed as soon as possible, that is, as soon as they are no longer
|
|
||||||
visible to any open transaction. You may wish to set this to a
|
|
||||||
non-zero value on a primary server that is supporting hot standby
|
|
||||||
servers, as described in <xref linkend="hot-standby"/>. This allows
|
|
||||||
more time for queries on the standby to complete without incurring
|
|
||||||
conflicts due to early cleanup of rows. However, since the value
|
|
||||||
is measured in terms of number of write transactions occurring on the
|
|
||||||
primary server, it is difficult to predict just how much additional
|
|
||||||
grace time will be made available to standby queries.
|
|
||||||
This parameter can only be set in the <filename>postgresql.conf</filename>
|
|
||||||
file or on the server command line.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
You should also consider setting <varname>hot_standby_feedback</varname>
|
|
||||||
on standby server(s) as an alternative to using this parameter.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This does not prevent cleanup of dead rows which have reached the age
|
|
||||||
specified by <varname>old_snapshot_threshold</varname>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
@ -944,12 +944,11 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
|
|||||||
retained by replication slots.
|
retained by replication slots.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Similarly, <xref linkend="guc-hot-standby-feedback"/>
|
Similarly, <xref linkend="guc-hot-standby-feedback"/> on its own, without
|
||||||
and <xref linkend="guc-vacuum-defer-cleanup-age"/> provide protection against
|
also using a replication slot, provides protection against relevant rows
|
||||||
relevant rows being removed by vacuum, but the former provides no
|
being removed by vacuum, but provides no protection during any time period
|
||||||
protection during any time period when the standby is not connected,
|
when the standby is not connected. Replication slots overcome these
|
||||||
and the latter often needs to be set to a high value to provide adequate
|
disadvantages.
|
||||||
protection. Replication slots overcome these disadvantages.
|
|
||||||
</para>
|
</para>
|
||||||
<sect3 id="streaming-replication-slots-manipulation">
|
<sect3 id="streaming-replication-slots-manipulation">
|
||||||
<title>Querying and Manipulating Replication Slots</title>
|
<title>Querying and Manipulating Replication Slots</title>
|
||||||
@ -1910,17 +1909,6 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
|
|||||||
by newly-arrived streaming WAL entries after reconnection.
|
by newly-arrived streaming WAL entries after reconnection.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Another option is to increase <xref linkend="guc-vacuum-defer-cleanup-age"/>
|
|
||||||
on the primary server, so that dead rows will not be cleaned up as quickly
|
|
||||||
as they normally would be. This will allow more time for queries to
|
|
||||||
execute before they are canceled on the standby, without having to set
|
|
||||||
a high <varname>max_standby_streaming_delay</varname>. However it is
|
|
||||||
difficult to guarantee any specific execution-time window with this
|
|
||||||
approach, since <varname>vacuum_defer_cleanup_age</varname> is measured in
|
|
||||||
transactions executed on the primary server.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The number of query cancels and the reason for them can be viewed using
|
The number of query cancels and the reason for them can be viewed using
|
||||||
the <structname>pg_stat_database_conflicts</structname> system view on the standby
|
the <structname>pg_stat_database_conflicts</structname> system view on the standby
|
||||||
@ -2257,8 +2245,7 @@ HINT: You can then restart the server after making the necessary configuration
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
On the primary, parameters <xref linkend="guc-wal-level"/> and
|
On the primary, the <xref linkend="guc-wal-level"/> parameter can be used.
|
||||||
<xref linkend="guc-vacuum-defer-cleanup-age"/> can be used.
|
|
||||||
<xref linkend="guc-max-standby-archive-delay"/> and
|
<xref linkend="guc-max-standby-archive-delay"/> and
|
||||||
<xref linkend="guc-max-standby-streaming-delay"/> have no effect if set on
|
<xref linkend="guc-max-standby-streaming-delay"/> have no effect if set on
|
||||||
the primary.
|
the primary.
|
||||||
@ -2268,9 +2255,6 @@ HINT: You can then restart the server after making the necessary configuration
|
|||||||
On the standby, parameters <xref linkend="guc-hot-standby"/>,
|
On the standby, parameters <xref linkend="guc-hot-standby"/>,
|
||||||
<xref linkend="guc-max-standby-archive-delay"/> and
|
<xref linkend="guc-max-standby-archive-delay"/> and
|
||||||
<xref linkend="guc-max-standby-streaming-delay"/> can be used.
|
<xref linkend="guc-max-standby-streaming-delay"/> can be used.
|
||||||
<xref linkend="guc-vacuum-defer-cleanup-age"/> has no effect
|
|
||||||
as long as the server remains in standby mode, though it will
|
|
||||||
become relevant if the standby becomes primary.
|
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
@ -367,9 +367,6 @@ static inline void ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId l
|
|||||||
static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid);
|
static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid);
|
||||||
static void MaintainLatestCompletedXid(TransactionId latestXid);
|
static void MaintainLatestCompletedXid(TransactionId latestXid);
|
||||||
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid);
|
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid);
|
||||||
static void TransactionIdRetreatSafely(TransactionId *xid,
|
|
||||||
int retreat_by,
|
|
||||||
FullTransactionId rel);
|
|
||||||
|
|
||||||
static inline FullTransactionId FullXidRelativeTo(FullTransactionId rel,
|
static inline FullTransactionId FullXidRelativeTo(FullTransactionId rel,
|
||||||
TransactionId xid);
|
TransactionId xid);
|
||||||
@ -1709,10 +1706,7 @@ TransactionIdIsActive(TransactionId xid)
|
|||||||
* do about that --- data is only protected if the walsender runs continuously
|
* do about that --- data is only protected if the walsender runs continuously
|
||||||
* while queries are executed on the standby. (The Hot Standby code deals
|
* while queries are executed on the standby. (The Hot Standby code deals
|
||||||
* with such cases by failing standby queries that needed to access
|
* with such cases by failing standby queries that needed to access
|
||||||
* already-removed data, so there's no integrity bug.) The computed values
|
* already-removed data, so there's no integrity bug.)
|
||||||
* are also adjusted with vacuum_defer_cleanup_age, so increasing that setting
|
|
||||||
* on the fly is another easy way to make horizons move backwards, with no
|
|
||||||
* consequences for data integrity.
|
|
||||||
*
|
*
|
||||||
* Note: the approximate horizons (see definition of GlobalVisState) are
|
* Note: the approximate horizons (see definition of GlobalVisState) are
|
||||||
* updated by the computations done here. That's currently required for
|
* updated by the computations done here. That's currently required for
|
||||||
@ -1877,50 +1871,11 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
|
|||||||
TransactionIdOlder(h->data_oldest_nonremovable, kaxmin);
|
TransactionIdOlder(h->data_oldest_nonremovable, kaxmin);
|
||||||
/* temp relations cannot be accessed in recovery */
|
/* temp relations cannot be accessed in recovery */
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Compute the cutoff XID by subtracting vacuum_defer_cleanup_age.
|
|
||||||
*
|
|
||||||
* vacuum_defer_cleanup_age provides some additional "slop" for the
|
|
||||||
* benefit of hot standby queries on standby servers. This is quick
|
|
||||||
* and dirty, and perhaps not all that useful unless the primary has a
|
|
||||||
* predictable transaction rate, but it offers some protection when
|
|
||||||
* there's no walsender connection. Note that we are assuming
|
|
||||||
* vacuum_defer_cleanup_age isn't large enough to cause wraparound ---
|
|
||||||
* so guc.c should limit it to no more than the xidStopLimit threshold
|
|
||||||
* in varsup.c. Also note that we intentionally don't apply
|
|
||||||
* vacuum_defer_cleanup_age on standby servers.
|
|
||||||
*
|
|
||||||
* Need to use TransactionIdRetreatSafely() instead of open-coding the
|
|
||||||
* subtraction, to prevent creating an xid before
|
|
||||||
* FirstNormalTransactionId.
|
|
||||||
*/
|
|
||||||
Assert(TransactionIdPrecedesOrEquals(h->oldest_considered_running,
|
|
||||||
h->shared_oldest_nonremovable));
|
|
||||||
Assert(TransactionIdPrecedesOrEquals(h->shared_oldest_nonremovable,
|
|
||||||
h->data_oldest_nonremovable));
|
|
||||||
|
|
||||||
if (vacuum_defer_cleanup_age > 0)
|
Assert(TransactionIdPrecedesOrEquals(h->oldest_considered_running,
|
||||||
{
|
h->shared_oldest_nonremovable));
|
||||||
TransactionIdRetreatSafely(&h->oldest_considered_running,
|
Assert(TransactionIdPrecedesOrEquals(h->shared_oldest_nonremovable,
|
||||||
vacuum_defer_cleanup_age,
|
h->data_oldest_nonremovable));
|
||||||
h->latest_completed);
|
|
||||||
TransactionIdRetreatSafely(&h->shared_oldest_nonremovable,
|
|
||||||
vacuum_defer_cleanup_age,
|
|
||||||
h->latest_completed);
|
|
||||||
TransactionIdRetreatSafely(&h->data_oldest_nonremovable,
|
|
||||||
vacuum_defer_cleanup_age,
|
|
||||||
h->latest_completed);
|
|
||||||
/* defer doesn't apply to temp relations */
|
|
||||||
|
|
||||||
|
|
||||||
Assert(TransactionIdPrecedesOrEquals(h->oldest_considered_running,
|
|
||||||
h->shared_oldest_nonremovable));
|
|
||||||
Assert(TransactionIdPrecedesOrEquals(h->shared_oldest_nonremovable,
|
|
||||||
h->data_oldest_nonremovable));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether there are replication slots requiring an older xmin.
|
* Check whether there are replication slots requiring an older xmin.
|
||||||
@ -1947,8 +1902,8 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
|
|||||||
h->slot_catalog_xmin);
|
h->slot_catalog_xmin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible that slots / vacuum_defer_cleanup_age backed up the
|
* It's possible that slots backed up the horizons further than
|
||||||
* horizons further than oldest_considered_running. Fix.
|
* oldest_considered_running. Fix.
|
||||||
*/
|
*/
|
||||||
h->oldest_considered_running =
|
h->oldest_considered_running =
|
||||||
TransactionIdOlder(h->oldest_considered_running,
|
TransactionIdOlder(h->oldest_considered_running,
|
||||||
@ -2490,15 +2445,9 @@ GetSnapshotData(Snapshot snapshot)
|
|||||||
*/
|
*/
|
||||||
oldestfxid = FullXidRelativeTo(latest_completed, oldestxid);
|
oldestfxid = FullXidRelativeTo(latest_completed, oldestxid);
|
||||||
|
|
||||||
/* apply vacuum_defer_cleanup_age */
|
|
||||||
def_vis_xid_data = xmin;
|
|
||||||
TransactionIdRetreatSafely(&def_vis_xid_data,
|
|
||||||
vacuum_defer_cleanup_age,
|
|
||||||
oldestfxid);
|
|
||||||
|
|
||||||
/* Check whether there's a replication slot requiring an older xmin. */
|
/* Check whether there's a replication slot requiring an older xmin. */
|
||||||
def_vis_xid_data =
|
def_vis_xid_data =
|
||||||
TransactionIdOlder(def_vis_xid_data, replication_slot_xmin);
|
TransactionIdOlder(xmin, replication_slot_xmin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rows in non-shared, non-catalog tables possibly could be vacuumed
|
* Rows in non-shared, non-catalog tables possibly could be vacuumed
|
||||||
@ -4320,44 +4269,6 @@ GlobalVisCheckRemovableXid(Relation rel, TransactionId xid)
|
|||||||
return GlobalVisTestIsRemovableXid(state, xid);
|
return GlobalVisTestIsRemovableXid(state, xid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Safely retract *xid by retreat_by, store the result in *xid.
|
|
||||||
*
|
|
||||||
* Need to be careful to prevent *xid from retreating below
|
|
||||||
* FirstNormalTransactionId during epoch 0. This is important to prevent
|
|
||||||
* generating xids that cannot be converted to a FullTransactionId without
|
|
||||||
* wrapping around.
|
|
||||||
*
|
|
||||||
* If retreat_by would lead to a too old xid, FirstNormalTransactionId is
|
|
||||||
* returned instead.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
TransactionIdRetreatSafely(TransactionId *xid, int retreat_by, FullTransactionId rel)
|
|
||||||
{
|
|
||||||
TransactionId original_xid = *xid;
|
|
||||||
FullTransactionId fxid;
|
|
||||||
uint64 fxid_i;
|
|
||||||
|
|
||||||
Assert(TransactionIdIsNormal(original_xid));
|
|
||||||
Assert(retreat_by >= 0); /* relevant GUCs are stored as ints */
|
|
||||||
AssertTransactionIdInAllowableRange(original_xid);
|
|
||||||
|
|
||||||
if (retreat_by == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fxid = FullXidRelativeTo(rel, original_xid);
|
|
||||||
fxid_i = U64FromFullTransactionId(fxid);
|
|
||||||
|
|
||||||
if ((fxid_i - FirstNormalTransactionId) <= retreat_by)
|
|
||||||
*xid = FirstNormalTransactionId;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*xid = TransactionIdRetreatedBy(original_xid, retreat_by);
|
|
||||||
Assert(TransactionIdIsNormal(*xid));
|
|
||||||
Assert(NormalTransactionIdPrecedes(*xid, original_xid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a 32 bit transaction id into 64 bit transaction id, by assuming it
|
* Convert a 32 bit transaction id into 64 bit transaction id, by assuming it
|
||||||
* is within MaxTransactionId / 2 of XidFromFullTransactionId(rel).
|
* is within MaxTransactionId / 2 of XidFromFullTransactionId(rel).
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
#include "utils/timestamp.h"
|
#include "utils/timestamp.h"
|
||||||
|
|
||||||
/* User-settable GUC parameters */
|
/* User-settable GUC parameters */
|
||||||
int vacuum_defer_cleanup_age;
|
|
||||||
int max_standby_archive_delay = 30 * 1000;
|
int max_standby_archive_delay = 30 * 1000;
|
||||||
int max_standby_streaming_delay = 30 * 1000;
|
int max_standby_streaming_delay = 30 * 1000;
|
||||||
bool log_recovery_conflict_waits = false;
|
bool log_recovery_conflict_waits = false;
|
||||||
|
@ -2576,15 +2576,6 @@ struct config_int ConfigureNamesInt[] =
|
|||||||
NULL, NULL, NULL
|
NULL, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
{"vacuum_defer_cleanup_age", PGC_SIGHUP, REPLICATION_PRIMARY,
|
|
||||||
gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any."),
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
&vacuum_defer_cleanup_age,
|
|
||||||
0, 0, 1000000, /* see ComputeXidHorizons */
|
|
||||||
NULL, NULL, NULL
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
|
{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
|
||||||
gettext_noop("Age at which VACUUM should trigger failsafe to avoid a wraparound outage."),
|
gettext_noop("Age at which VACUUM should trigger failsafe to avoid a wraparound outage."),
|
||||||
|
@ -329,7 +329,6 @@
|
|||||||
# method to choose sync standbys, number of sync standbys,
|
# method to choose sync standbys, number of sync standbys,
|
||||||
# and comma-separated list of application_name
|
# and comma-separated list of application_name
|
||||||
# from standby(s); '*' = all
|
# from standby(s); '*' = all
|
||||||
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
|
|
||||||
|
|
||||||
# - Standby Servers -
|
# - Standby Servers -
|
||||||
|
|
||||||
|
@ -234,9 +234,6 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
|
|||||||
* we only modify the new cluster, so only use it there. If there is a
|
* we only modify the new cluster, so only use it there. If there is a
|
||||||
* crash, the new cluster has to be recreated anyway. fsync=off is a big
|
* crash, the new cluster has to be recreated anyway. fsync=off is a big
|
||||||
* win on ext4.
|
* win on ext4.
|
||||||
*
|
|
||||||
* Force vacuum_defer_cleanup_age to 0 on the new cluster, so that
|
|
||||||
* vacuumdb --freeze actually freezes the tuples.
|
|
||||||
*/
|
*/
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"\"%s/pg_ctl\" -w -l \"%s/%s\" -D \"%s\" -o \"-p %d -b%s %s%s\" start",
|
"\"%s/pg_ctl\" -w -l \"%s/%s\" -D \"%s\" -o \"-p %d -b%s %s%s\" start",
|
||||||
@ -244,7 +241,7 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
|
|||||||
log_opts.logdir,
|
log_opts.logdir,
|
||||||
SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
|
SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
|
||||||
(cluster == &new_cluster) ?
|
(cluster == &new_cluster) ?
|
||||||
" -c synchronous_commit=off -c fsync=off -c full_page_writes=off -c vacuum_defer_cleanup_age=0" : "",
|
" -c synchronous_commit=off -c fsync=off -c full_page_writes=off" : "",
|
||||||
cluster->pgopts ? cluster->pgopts : "", socket_string);
|
cluster->pgopts ? cluster->pgopts : "", socket_string);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "storage/standbydefs.h"
|
#include "storage/standbydefs.h"
|
||||||
|
|
||||||
/* User-settable GUC parameters */
|
/* User-settable GUC parameters */
|
||||||
extern PGDLLIMPORT int vacuum_defer_cleanup_age;
|
|
||||||
extern PGDLLIMPORT int max_standby_archive_delay;
|
extern PGDLLIMPORT int max_standby_archive_delay;
|
||||||
extern PGDLLIMPORT int max_standby_streaming_delay;
|
extern PGDLLIMPORT int max_standby_streaming_delay;
|
||||||
extern PGDLLIMPORT bool log_recovery_conflict_waits;
|
extern PGDLLIMPORT bool log_recovery_conflict_waits;
|
||||||
|
Reference in New Issue
Block a user