*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 5148,5153 **** COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
--- 5148,5168 ----
+
+ multixact_freeze_table_age (integer)
+
+ multixact_freeze_table_age> configuration parameter
+
+
+
+ VACUUM> performs a whole-table scan if the table's
+ pg_class>.relminmxid> field has reached
+ the age specified by this setting. The default is 5 million multixacts.
+ For more information see .
+
+
+
+
vacuum_freeze_min_age (integer)
***************
*** 5169,5174 **** COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
--- 5184,5205 ----
+
+ multixact_freeze_min_age (integer)
+
+ multixact_freeze_min_age> configuration parameter
+
+
+
+ Specifies the cutoff age (in multixacts) that VACUUM>
+ should use to decide whether to replace multixact IDs with a newer
+ transaction ID or multixact ID while scanning a table. The default
+ is 1 million multixacts.
+ For more information see .
+
+
+
+
bytea_output (enum)
*** a/doc/src/sgml/maintenance.sgml
--- b/doc/src/sgml/maintenance.sgml
***************
*** 599,604 **** HINT: Stop the postmaster and use a standalone backend to VACUUM in "mydb".
--- 599,632 ----
page for details about using a single-user backend.
+
+ Multixacts and Wraparound
+
+
+ Multixact ID
+ wraparound
+
+
+
+
+ Similar to transaction IDs, Multixact IDs are implemented as a 32-bit
+ counter and corresponding storage which requires careful aging management,
+ storage cleanup, and wraparound handling. Multixacts are used to implement
+ row locking by multiple transactions: since there is limited space in the
+ tuple header to store lock information, that information is stored separately
+ and only a reference to it is in the tuple header. As with transaction IDs,
+ VACUUM> is in charge of removing old values. Each
+ VACUUM> run sets a mark in each table that indicates what's the
+ oldest possible value still stored in it; every time this value is older than
+ , a full-table scan is forced.
+ Any Multixact older than is
+ replaced by something else, which can be the zero value, a lone transaction ID,
+ or a newer Multixact. Eventually, as all tables in all databases have been
+ scanned and their oldest Multixact values are advanced, on-disk storage for
+ Multixact can be removed.
+
+
*** a/src/backend/commands/vacuum.c
--- b/src/backend/commands/vacuum.c
***************
*** 55,60 ****
--- 55,62 ----
*/
int vacuum_freeze_min_age;
int vacuum_freeze_table_age;
+ int multixact_freeze_min_age;
+ int multixact_freeze_table_age;
/* A few variables that don't seem worth passing around as parameters */
***************
*** 406,411 **** vacuum_set_xid_limits(int freeze_min_age,
--- 408,414 ----
MultiXactId *mxactFullScanLimit)
{
int freezemin;
+ int mxid_freezemin;
TransactionId limit;
TransactionId safeLimit;
MultiXactId mxactLimit;
***************
*** 462,472 **** vacuum_set_xid_limits(int freeze_min_age,
*freezeLimit = limit;
/*
! * 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;
--- 465,475 ----
*freezeLimit = limit;
/*
! * Determine the minimum multixact freeze age to use: as specified by
! * caller, or multixact_freeze_min_age.
*/
! mxid_freezemin = Min(freeze_min_age, multixact_freeze_min_age);
! mxactLimit = GetOldestMultiXactId() - mxid_freezemin;
if (mxactLimit < FirstMultiXactId)
mxactLimit = FirstMultiXactId;
*multiXactCutoff = mxactLimit;
***************
*** 503,516 **** vacuum_set_xid_limits(int freeze_min_age,
/*
* 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.
*/
mxactLimit = ReadNextMultiXactId() - freezetable;
if (mxactLimit < FirstMultiXactId)
mxactLimit = FirstMultiXactId;
*mxactFullScanLimit = mxactLimit;
}
}
/*
--- 506,524 ----
/*
* Compute MultiXactId limit to cause a full-table vacuum, being
* careful not to generate an invalid multi. We just copy the logic
! * from plain XIDs here.
*/
+ freezetable = multixact_freeze_table_age;
mxactLimit = ReadNextMultiXactId() - freezetable;
if (mxactLimit < FirstMultiXactId)
mxactLimit = FirstMultiXactId;
*mxactFullScanLimit = mxactLimit;
}
+ else
+ {
+ Assert(mxactFullScanLimit == NULL);
+ }
}
/*
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 1907,1912 **** static struct config_int ConfigureNamesInt[] =
--- 1907,1932 ----
},
{
+ {"multixact_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Minimum age at which VACUUM should freeze a MultiXactId in a table row."),
+ NULL
+ },
+ &multixact_freeze_min_age,
+ 1000000, 0, 200000000,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"multixact_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Multixact age at which VACUUM should scan whole table to freeze tuples."),
+ NULL
+ },
+ &multixact_freeze_table_age,
+ 5000000, 0, 200000000,
+ NULL, NULL, NULL
+ },
+
+ {
{"vacuum_defer_cleanup_age", PGC_SIGHUP, REPLICATION_MASTER,
gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any."),
NULL
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 492,497 ****
--- 492,499 ----
#lock_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000
+ #multixact_freeze_min_age = 1000000
+ #multixact_freeze_table_age = 5000000
#bytea_output = 'hex' # hex, escape
#xmlbinary = 'base64'
#xmloption = 'content'
*** a/src/include/commands/vacuum.h
--- b/src/include/commands/vacuum.h
***************
*** 136,141 **** extern PGDLLIMPORT int default_statistics_target; /* PGDLLIMPORT for
--- 136,143 ----
* PostGIS */
extern int vacuum_freeze_min_age;
extern int vacuum_freeze_table_age;
+ extern int multixact_freeze_min_age;
+ extern int multixact_freeze_table_age;
/* in commands/vacuum.c */