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

Reply via email to