Robert Haas escribió: > On Fri, Jan 3, 2014 at 9:11 AM, Alvaro Herrera <alvhe...@2ndquadrant.com> > wrote:
> Yeah, this stuff is definitely underdocumented relative to vacuum right now. I have added a paragraph or two. It's a (probably insufficient) start. I would like to add a sample query to monitor usage, but I just realize we don't have a function such as age(xid) to expose this info usefully. We can't introduce one in 9.3 now, but probably we should do so in HEAD. > Also, while multixactid_freeze_min_age should be low, perhaps a > million as you suggest, multixactid_freeze_table_age should NOT be > lowered to 3 million or anything like it. If you do that, people who > are actually doing lots of row locking will start getting many more > full-table scans. We want to avoid that at all cost. I'd probably > make the default the same as for vacuum_freeze_table_age, so that > mxids only cause extra full-table scans if they're being used more > quickly than xids. I agree that the freeze_table limit should not be low, but 150 million seems too high. Not really sure what's a good value here. Here's a first cut at this. Note I have omitted a setting equivalent to autovacuum_freeze_max_age, but I think we should have one too. -- Álvaro Herrera http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
*** 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 ---- </listitem> </varlistentry> + <varlistentry id="guc-multixact-freeze-table-age" xreflabel="multixact_freeze_table_age"> + <term><varname>multixact_freeze_table_age</varname> (<type>integer</type>)</term> + <indexterm> + <primary><varname>multixact_freeze_table_age</> configuration parameter</primary> + </indexterm> + <listitem> + <para> + <command>VACUUM</> performs a whole-table scan if the table's + <structname>pg_class</>.<structfield>relminmxid</> field has reached + the age specified by this setting. The default is 5 million multixacts. + For more information see <xref linkend="multixact-wraparound">. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-vacuum-freeze-min-age" xreflabel="vacuum_freeze_min_age"> <term><varname>vacuum_freeze_min_age</varname> (<type>integer</type>)</term> <indexterm> *************** *** 5169,5174 **** COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; --- 5184,5205 ---- </listitem> </varlistentry> + <varlistentry id="guc-multixact-freeze-min-age" xreflabel="multixact_freeze_min_age"> + <term><varname>multixact_freeze_min_age</varname> (<type>integer</type>)</term> + <indexterm> + <primary><varname>multixact_freeze_min_age</> configuration parameter</primary> + </indexterm> + <listitem> + <para> + Specifies the cutoff age (in multixacts) that <command>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 <xref linkend="multixact-wraparound">. + </para> + </listitem> + </varlistentry> + <varlistentry id="guc-bytea-output" xreflabel="bytea_output"> <term><varname>bytea_output</varname> (<type>enum</type>)</term> <indexterm> *** 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. </para> + <sect3 id="multixact-wraparound"> + <title>Multixacts and Wraparound</title> + + <indexterm> + <primary>Multixact ID</primary> + <secondary>wraparound</secondary> + </indexterm> + <!-- how about another index entry primary="wraparound", + secondary="multixact", and the same for xids? --> + + <para> + 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, + <command>VACUUM</> is in charge of removing old values. Each + <command>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 + <xref linkend="guc-multixact-freeze-table-age">, a full-table scan is forced. + Any Multixact older than <xref linkend="guc-multixact-freeze-min-age"> 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. + </para> + </sect3> </sect2> <sect2 id="autovacuum"> *** 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 */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers